﻿#include "pch.h"
#include "StdAfx.h"
#include "Triangle.h"
#include <math.h>
#define ROUND(d) int(d + 0.5)
#define PI 3.1415926
CTriangle::CTriangle(void)
{
}

CTriangle::CTriangle(CP2 P0, CP2 P1, CP2 P2)
{
	point0.x = ROUND(P0.x);
	point0.y = ROUND(P0.y);
	point0.c = P0.c;
	point1.x = ROUND(P1.x);
	point1.y = ROUND(P1.y);
	point1.c = P1.c;
	point2.x = ROUND(P2.x);
	point2.y = ROUND(P2.y);
	point2.c = P2.c;
}

void CTriangle::SetPoint(CP3 P0, CP3 P1, CP3 P2, CVector v0, CVector v1, CVector v2)
{
	this->P0 = P0;
	this->P1 = P1;
	this->P2 = P2;
	this->v0 = v0;
	this->v1 = v1;
	this->v2 = v2;
	this->point0.x = P0.x;
	this->point0.y = P0.y;
	this->point0.c = P0.c;
	this->point0.n = v0;
	this->point1.x = P1.x;
	this->point1.y = P1.y;
	this->point1.c = P0.c;
	this->point1.n = v1;

	this->point2.x = P2.x;
	this->point2.y = P2.y;
	this->point2.c = P0.c;
	this->point2.n = v2;


}

void CTriangle::SetPointTex(CP3 P0, CP3 P1, CP3 P2, CVector v0, CVector v1, CVector v2, CT2 T0, CT2 T1, CT2 T2)
{
	this->P0 = P0;
	this->P1 = P1;
	this->P2 = P2;

	this->point0.x = P0.x;
	this->point0.y = P0.y;
	this->point0.c = P0.c;
	this->point0.n = v0;
	this->point0.t = T0;

	this->point1.x = P1.x;
	this->point1.y = P1.y;
	this->point1.c = P0.c;
	this->point1.n = v1;
	this->point1.t = T1;

	this->point2.x = P2.x;
	this->point2.y = P2.y;
	this->point2.c = P0.c;
	this->point2.n = v2;
	this->point2.t = T2;

}
CTriangle::~CTriangle(void)
{
}
void CTriangle::GouraudShader(CDC* pDC)
{
	SortVertex();//point0点为y坐标最小的点,point1点为y坐标最大的点,point2点的y坐标位于二者之间。如果y值相同，取x最小的点
	//定义三角形覆盖的扫描线条数
	int nTotalScanLine = point1.y - point0.y + 1;
	//定义span的起点与终点数组
	SpanLeft = new CPoint2[nTotalScanLine];//跨度坐标数组
	SpanRight = new CPoint2[nTotalScanLine];//跨度右边数组

	//判断三角形与P0P1边的位置关系，0-1-2为右手系
	int nDeltz = (point1.x - point0.x) * (point2.y - point1.y) - (point1.y - point0.y) * (point2.x - point1.x);//点矢量叉积的z坐标
	if (nDeltz > 0)//三角形位于P0P1边的左侧
	{
		nIndex = 0;
		DDA(point0, point2, TRUE);
		DDA(point2, point1, TRUE);
		nIndex = 0;
		DDA(point0, point1, FALSE);
	}
	else//三角形位于P0P1边的右侧
	{
		nIndex = 0;
		DDA(point0, point1, TRUE);
		nIndex = 0;
		DDA(point0, point2, FALSE);
		DDA(point2, point1, FALSE);
	}
	CRGB clr;
	for (int y = point0.y; y < point1.y; y++)//下闭上开
	{
		int n = y - point0.y;
		for (int x = SpanLeft[n].x; x < SpanRight[n].x; x++)//左闭右开
		{
			clr = LinearInterp(x, SpanLeft[n].x, SpanRight[n].x, SpanLeft[n].c, SpanRight[n].c);
			pDC->SetPixelV(x, y, RGB(clr.red * 255, clr.green * 255, clr.blue * 255));
		}
	}
	if (SpanLeft)
	{
		delete[]SpanLeft;
		SpanLeft = NULL;
	}
	if (SpanRight)
	{
		delete[]SpanRight;
		SpanRight = NULL;
	}
}

void CTriangle::GouraudShaderXin(CDC* pDC, CP3 ViewPoint, CLighting* pLight, CMaterial* pMaterial, int nLightNumber, CTexture* pTexture)
{
	double CurrentDepth = 0.0;
	CVector Vector01(P0, P1), Vector02(P0, P2);
	CVector fNormal = CrossProduct(Vector01, Vector02);
	double A = fNormal.x, B = fNormal.y, C = fNormal.z;
	double D = -A * P0.x - B * P0.y - C * P0.z;
	if (fabs(C) < 1e-4) {
		C = 1.0;
	}
	double DepthStep = -A / C;
	SortVertex();//point0点为y坐标最小的点,point1点为y坐标最大的点,point2点的y坐标位于二者之间。如果y值相同，取x最小的点
	//定义三角形覆盖的扫描线条数
	int nTotalScanLine = point1.y - point0.y + 1;
	//定义span的起点与终点数组
	SpanLeft = new CPoint2[nTotalScanLine];//跨度坐标数组
	SpanRight = new CPoint2[nTotalScanLine];//跨度右边数组

	//判断三角形与P0P1边的位置关系，0-1-2为右手系
	int nDeltz = (point1.x - point0.x) * (point2.y - point1.y) - (point1.y - point0.y) * (point2.x - point1.x);//点矢量叉积的z坐标
	if (nDeltz > 0)//三角形位于P0P1边的左侧
	{
		nIndex = 0;
		EdgeGroundXin(point0, point2, TRUE);
		EdgeGroundXin(point2, point1, TRUE);
		nIndex = 0;
		EdgeGroundXin(point0, point1, FALSE);
	}
	else//三角形位于P0P1边的右侧
	{
		nIndex = 0;
		EdgeGroundXin(point0, point1, TRUE);
		nIndex = 0;
		EdgeGroundXin(point0, point2, FALSE);
		EdgeGroundXin(point2, point1, FALSE);
	}
	CRGB clr;
	for (int y = point0.y; y < point1.y; y++)//下闭上开
	{
		int n = y - point0.y;
		BOOL bInFlag = FALSE;
		
		for (int x = SpanLeft[n].x; x < SpanRight[n].x; x++)//左闭右开
		{
			if (bInFlag == FALSE) {
				CurrentDepth = -(A * x + B * y + D) / C;
				bInFlag = TRUE;
				x -= 1;
			}
			else {
				CT2 Texture = LinearInterp(x, SpanLeft[n].x, SpanRight[n].x, SpanLeft[n].t, SpanRight[n].t);
				CVector ptNormal = LinearInterp(x, SpanLeft[n].x, SpanRight[n].x, SpanLeft[n].n, SpanRight[n].n);
				Texture.c = GetTexture(ROUND(Texture.u), ROUND(Texture.v), pTexture);
				pMaterial->SetDiffuse(Texture.c);
				pMaterial->SetAmbient(Texture.c);
				CRGB Intensity = pLight->Illuminate(ViewPoint, CP3(x, y, CurrentDepth), ptNormal, nLightNumber, pMaterial);
				pDC->SetPixelV(x, y, RGB(Intensity.red * 255, Intensity.green * 255, Intensity.blue * 255));
				CurrentDepth += DepthStep;
			}
		}	
	}
	if (SpanLeft)
	{
		delete[]SpanLeft;
		SpanLeft = NULL;
	}
	if (SpanRight)
	{
		delete[]SpanRight;
		SpanRight = NULL;
	}
}

void CTriangle::PhongShader(CDC* pDC, CP3 ViewPoint, CLighting* pLight, CMaterial* pMaterial, int nLightNumber)
{
	double CurrentDepth = 0.0;
	CVector Vector01(P0, P1), Vector02(P0, P2);
	CVector fNormal = CrossProduct(Vector01,Vector02);
	double A = fNormal.x, B = fNormal.y, C = fNormal.z;
	double D = -A * P0.x - B * P0.y - C * P0.z;
	if (fabs(C) < 1e-4) {
		C = 1.0;
	}
	double DepthStep = -A / C;
	SortVertex();
	int nTotalLine = point1.y - point0.y + 1;
	//定义span的起点与终点
	SpanLeft = new CPoint3[nTotalLine];
	SpanRight = new CPoint3[nTotalLine];
	int nDeltz = (point1.x - point0.x) * (point2.y - point1.y) - (point1.y - point0.y) * (point2.x - point1.x);
	if (nDeltz > 0) {
		nIndex = 0;
		Edge(point0, point2, TRUE);
		Edge(point2, point1, TRUE);
		nIndex = 0;
		Edge(point0, point1, FALSE);
	}
	else {
		nIndex = 0;
		Edge(point0, point1, TRUE);
		nIndex = 0;
		Edge(point0, point2, FALSE);
		Edge(point2, point1, FALSE);
	}
	for (int y = point0.y; y < point1.y; y++) {
		int n = y - point0.y;
		BOOL bInFlag = FALSE;
		for (int x = SpanLeft[n].x; x < SpanRight[n].x; x++) {
			if (bInFlag == FALSE) {
				CurrentDepth = -(A * x + B * y + D) / C;
				bInFlag = TRUE;
				x -= 1;
			}
			else {
				CVector ptNormal = LinearInterp(x, SpanLeft[n].x, SpanRight[n].x, SpanLeft[n].n, SpanRight[n].n);
				ptNormal = ptNormal.Normalize();
				CRGB Intensity = pLight->Illuminate(ViewPoint, CP3(x, y, CurrentDepth), ptNormal, nLightNumber,pMaterial);
				pDC->SetPixelV(x, y, RGB(Intensity.red * 255, Intensity.green * 255, Intensity.blue * 255));
				CurrentDepth += DepthStep;
			}
		}
	}
	if (SpanLeft)
	{
		delete[]SpanLeft;
		SpanLeft = NULL;
	}
	if (SpanRight)
	{
		delete[]SpanRight;
		SpanRight = NULL;
	}
}

void CTriangle::PhongShaderTex(CDC* pDC, CP3 ViewPoint, CLighting* pLight, CMaterial* pMaterial, int nLightNumber, CTexture* pTexture)
{
	double CurrentDepth = 0.0;
	CVector Vector01(P0, P1), Vector02(P0, P2);
	CVector fNormal = CrossProduct(Vector01, Vector02);
	double A = fNormal.x, B = fNormal.y, C = fNormal.z;
	double D = -A * P0.x - B * P0.y - C * P0.z;
	if (fabs(C) < 1e-4) {
		C = 1.0;
	}
	double DepthStep = -A / C;
	SortVertex();
	int nTotalLine = point1.y - point0.y + 1;
	//定义span的起点与终点
	SpanLeft = new CPoint2[nTotalLine];
	SpanRight = new CPoint2[nTotalLine];
	int nDeltz = (point1.x - point0.x) * (point2.y - point1.y) - (point1.y - point0.y) * (point2.x - point1.x);
	if (nDeltz > 0) {
		nIndex = 0;
		Edge(point0, point2, TRUE);
		Edge(point2, point1, TRUE);
		nIndex = 0;
		Edge(point0, point1, FALSE);
	}
	else {
		nIndex = 0;
		Edge(point0, point1, TRUE);
		nIndex = 0;
		Edge(point0, point2, FALSE);
		Edge(point2, point1, FALSE);
	}
	for (int y = point0.y; y < point1.y; y++) {
		int n = y - point0.y;
		BOOL bInFlag = FALSE;
		for (int x = SpanLeft[n].x; x < SpanRight[n].x; x++) {
			if (bInFlag == FALSE) {
				CurrentDepth = -(A * x + B * y + D) / C;
				bInFlag = TRUE;
				x -= 1;
			}
			else {
				CVector ptNormal = LinearInterp(x, SpanLeft[n].x, SpanRight[n].x, SpanLeft[n].n, SpanRight[n].n);
				CT2 Texture = LinearInterp(x, SpanLeft[n].x, SpanRight[n].x, SpanLeft[n].t, SpanRight[n].t);
				CRGB DIffuse = pMaterial->M_Diffuse, Ambient = pMaterial->M_Ambient;
				if (ROUND(Texture.u) < 0 || ROUND(Texture.v) < 0 || ROUND(Texture.u) > pTexture->bmp.bmWidth - 1 || ROUND(Texture.v) > pTexture->bmp.bmHeight - 1) {
					Texture.c = DIffuse;//图像外使用建模体材质
				}
				else {
					Texture.c = GetTexture(Texture.u, Texture.v, pTexture);//覆盖的地方使用图形纹理
				}
				pMaterial->SetDiffuse(Texture.c);				
				pMaterial->SetAmbient(Texture.c);
				CRGB Intensity = pLight->Illuminate(ViewPoint, CP3(ROUND(x), y, CurrentDepth), ptNormal, nLightNumber, pMaterial);
				pDC->SetPixelV(x, y, RGB(Intensity.red * 255, Intensity.green * 255, Intensity.blue * 255));
				CurrentDepth += DepthStep;
			}
		}
	}
	if (SpanLeft)
	{
		delete[]SpanLeft;
		SpanLeft = NULL;
	}
	if (SpanRight)
	{
		delete[]SpanRight;
		SpanRight = NULL;
	}
}

void CTriangle::PhongShaderTex3D(CDC* pDC, CP3 ViewPoint, CLighting* pLight, CMaterial* pMaterial, int nLightNumber)
{
	double CurrentDepth = 0.0;
	CVector Vector01(P0, P1), Vector02(P0, P2);
	CVector fNormal = CrossProduct(Vector01, Vector02);
	double A = fNormal.x, B = fNormal.y, C = fNormal.z;
	double D = -A * P0.x - B * P0.y - C * P0.z;
	if (fabs(C) < 1e-4) {
		C = 1.0;
	}
	double DepthStep = -A / C;
	SortVertex();
	int nTotalLine = point1.y - point0.y + 1;
	//定义span的起点与终点
	SpanLeft = new CPoint3[nTotalLine];
	SpanRight = new CPoint3[nTotalLine];
	int nDeltz = (point1.x - point0.x) * (point2.y - point1.y) - (point1.y - point0.y) * (point2.x - point1.x);
	if (nDeltz > 0) {
		nIndex = 0;
		Edge(point0, point2, TRUE);
		Edge(point2, point1, TRUE);
		nIndex = 0;
		Edge(point0, point1, FALSE);
	}
	else {
		nIndex = 0;
		Edge(point0, point1, TRUE);
		nIndex = 0;
		Edge(point0, point2, FALSE);
		Edge(point2, point1, FALSE);
	}
	for (int y = point0.y; y < point1.y; y++) {
		int n = y - point0.y;
		BOOL bInFlag = FALSE;
		for (int x = SpanLeft[n].x; x < SpanRight[n].x; x++) {
			if (bInFlag == FALSE) {
				CurrentDepth = -(A * x + B * y + D) / C;
				bInFlag = TRUE;
				x -= 1;
			}
			else {
				CVector ptNormal = LinearInterp(x, SpanLeft[n].x, SpanRight[n].x, SpanLeft[n].n, SpanRight[n].n);//法矢量
				CT2 temp = LinearInterp(x, SpanLeft[n].x, SpanRight[n].x, SpanLeft[n].t, SpanRight[n].t);
				CT3 Texture = CT3(temp.u, temp.v, 0);
				Texture.c = ReadWoodTexture(Texture);
				ptNormal = ptNormal.Normalize();
				CRGB Intensity = pLight->Illuminate(ViewPoint, CP3(ROUND(x), y, CurrentDepth), ptNormal, nLightNumber, pMaterial);
				pDC->SetPixelV(x, y, RGB(Intensity.red * 255, Intensity.green * 255, Intensity.blue * 255));
				CurrentDepth += DepthStep;
			}
		}
	}
	if (SpanLeft)
	{
		delete[]SpanLeft;
		SpanLeft = NULL;
	}
	if (SpanRight)
	{
		delete[]SpanRight;
		SpanRight = NULL;
	}
}

void CTriangle::PhongShaderXIn(CDC* pDC, CP3 ViewPoint, CLighting* pLight, CMaterial* pMaterial, int nLightNumber, CTexture* pTexture)
{
	double CurrentDepth = 0.0;
	CVector Vector01(P0, P1), Vector02(P0, P2);
	CVector fNormal = CrossProduct(Vector01, Vector02);
	double A = fNormal.x, B = fNormal.y, C = fNormal.z;
	double D = -A * P0.x - B * P0.y - C * P0.z;
	if (fabs(C) < 1e-4) {
		C = 1.0;
	}
	double DepthStep = -A / C;
	SortVertex();
	int nTotalLine = point1.y - point0.y + 1;
	//定义span的起点与终点
	SpanLeft = new CPoint2[nTotalLine];
	SpanRight = new CPoint2[nTotalLine];
	int nDeltz = (point1.x - point0.x) * (point2.y - point1.y) - (point1.y - point0.y) * (point2.x - point1.x);
	if (nDeltz > 0) {
		nIndex = 0;
		Edge(point0, point2, TRUE);
		Edge(point2, point1, TRUE);
		nIndex = 0;
		Edge(point0, point1, FALSE);
	}
	else {
		nIndex = 0;
		Edge(point0, point1, TRUE);
		nIndex = 0;
		Edge(point0, point2, FALSE);
		Edge(point2, point1, FALSE);
	}
	for (int y = point0.y; y < point1.y; y++) {
		int n = y - point0.y;
		BOOL bInFlag = FALSE;
		for (int x = SpanLeft[n].x; x < SpanRight[n].x; x++) {
			if (bInFlag == FALSE) {
				CurrentDepth = -(A * x + B * y + D) / C;
				bInFlag = TRUE;
				x -= 1;
			}
			else {
				CVector ptNormal = LinearInterp(x, SpanLeft[n].x, SpanRight[n].x, SpanLeft[n].n, SpanRight[n].n);
				CT2 Texture = LinearInterp(x, SpanLeft[n].x, SpanRight[n].x, SpanLeft[n].t, SpanRight[n].t);
				Texture.c = GetTexture(ROUND(Texture.u), ROUND(Texture.v), pTexture);
				pMaterial->SetDiffuse(Texture.c);
				pMaterial->SetAmbient(Texture.c);
				CRGB Intensity = pLight->Illuminate(ViewPoint, CP3(x, y, CurrentDepth), ptNormal, nLightNumber, pMaterial);
				pDC->SetPixelV(x, y, RGB(Intensity.red * 255, Intensity.green * 255, Intensity.blue * 255));
				CurrentDepth += DepthStep;
			}
		}
	}
	if (SpanLeft)
	{
		delete[]SpanLeft;
		SpanLeft = NULL;
	}
	if (SpanRight)
	{
		delete[]SpanRight;
		SpanRight = NULL;
	}
}

CRGB CTriangle::ReadWoodTexture(CT3 t)
{
	CP3 Point(t.u, t.v, t.w);
	/*if (int(floor(Point.y / 20)) % 2 == 0)
		return CRGB(0.8, 0.6,0.0);
	else
		return CRGB(0.5,0.3,0.0);*/
	double r = sqrt(Point.x * Point.x + Point.z * Point.z);
	double Alpha;
	if (Point.z == 0) {
		Alpha = PI / 2;
	}
	else {
		Alpha = atan(Point.x / Point.z);
	}
	r = r + 2 * sin(20 * Alpha + Point.y / 10);
	int grain = ROUND(r) % 40;
	if (grain < 20) {
		return CRGB(0.8, 0.6, 0.0);
	}
	else {
		return CRGB(0.5, 0.3, 0.0); 

	}
}

void CTriangle::Edge(CPoint2 PStart, CPoint2 PEnd, BOOL bFeature)
{
	int dx = PEnd.x - PStart.x;
	int dy = PEnd.y - PStart.y;
	double m = double(dx) / dy;
	double x = PStart.x;
	for (int y = PStart.y; y < PEnd.y; y++)
	{
		CVector vector = LinearInterp(y, PStart.y, PEnd.y, PStart.n, PEnd.n);
		CT2  texture = LinearInterp(y, PStart.y, PEnd.y, PStart.t, PEnd.t);
		if (bFeature)
			SpanLeft[nIndex++] = CPoint2(ROUND(x), y, vector, texture);
		else
			SpanRight[nIndex++] = CPoint2(ROUND(x), y, vector,texture);
		x += m;
	}
}

void CTriangle::EdgeGroundXin(CPoint2 PStart, CPoint2 PEnd, BOOL bFeature)
{
	int dx = PEnd.x - PStart.x;
	int dy = PEnd.y - PStart.y;
	double m = double(dx) / dy;
	double x = PStart.x;
	for (int y = PStart.y; y < PEnd.y; y++)
	{
		CVector vector = LinearInterp(y, PStart.y, PEnd.y, PStart.n, PEnd.n);
		CT2  texture = LinearInterp(y, PStart.y, PEnd.y, PStart.t, PEnd.t);
		if (bFeature)
			SpanLeft[nIndex++] = CPoint2(ROUND(x), y, vector, texture);
		else
			SpanRight[nIndex++] = CPoint2(ROUND(x), y, vector, texture);
		x += m;
		/*CRGB crColor = LinearInterp(y, PStart.y, PEnd.y, PStart.c, PEnd.c);
		CT2  texture = LinearInterp(y, PStart.y, PEnd.y, PStart.t, PEnd.t);
		if (bFeature)
			SpanLeft[nIndex++] = CPoint2(ROUND(x), y, crColor,texture);
		else
			SpanRight[nIndex++] = CPoint2(ROUND(x), y, crColor,texture);
		x += m;*/
	}
}

void CTriangle::DDA(CPoint2 PStart, CPoint2 PEnd, BOOL bFeature)
{
	int dx = PEnd.x - PStart.x;
	int dy = PEnd.y - PStart.y;
	double m = double(dx) / dy;
	double x = PStart.x;
	for (int y = PStart.y; y < PEnd.y; y++)
	{
		CRGB crColor = LinearInterp(y, PStart.y, PEnd.y, PStart.c, PEnd.c);
		if (bFeature)
			SpanLeft[nIndex++] = CPoint2(ROUND(x), y, crColor);
		else
			SpanRight[nIndex++] = CPoint2(ROUND(x), y, crColor);
		x += m;
	}
}

void CTriangle::SortVertex()
{
	CPoint2 pt[3];
	pt[0] = point0;
	pt[1] = point1;
	pt[2] = point2;
	for (int i = 0; i < 2; i++)
	{
		int min = i;
		for (int j = i + 1; j < 3; j++)
			if (pt[j].y < pt[min].y)
				min = j;
		CPoint2 pTemp = pt[i];
		pt[i] = pt[min];
		pt[min] = pTemp;
	}
	point0 = pt[0];
	point1 = pt[2];
	point2 = pt[1];
}

CRGB CTriangle::LinearInterp(double t, double tStart, double tEnd, CRGB cStart, CRGB cEnd)//颜色线性插值
{
	CRGB color;
	color = (tEnd - t) / (tEnd - tStart) * cStart + (t - tStart) / (tEnd - tStart) * cEnd;
	return color;
}

CVector CTriangle::LinearInterp(double t, double tStart, double tEnd, CVector vStart, CVector vEnd)
{
	CVector Vector;
	Vector = (tEnd - t) / (tEnd - tStart) * vStart + (t - tStart) / (tEnd - tStart) * vEnd;
	return Vector;
}

CT2 CTriangle::LinearInterp(double t, double tStart, double tEnd, CT2 texStart, CT2 texEnd)
{
	CT2 temp;
	temp = (tEnd - t) / (tEnd - tStart) * texStart + (t - tStart) / (tEnd - tStart) * texEnd;
	return temp;
}

CT3 CTriangle::LinearInterp(double t, double tStart, double tEnd, CT3 texStart, CT3 texEnd)
{
	/*CT3 temp;
	temp.u = (tEnd - t) / (tEnd - tStart) * texStart.u + (t - tStart) / (tEnd - tStart) * texEnd.u;
	temp.v = (tEnd - t) / (tEnd - tStart) * texStart.v + (t - tStart) / (tEnd - tStart) * texEnd.v;
	temp.w = 0;
	return temp;*/
	return CT3();
}

CRGB CTriangle::GetTexture(int u, int v, CTexture* pTexture)
{
	v = pTexture->bmp.bmHeight - 1 - v;
	int position = v * pTexture->bmp.bmWidthBytes + 4 * u;//颜色分量位置
	COLORREF color = RGB(pTexture->image[position + 2],pTexture->image[position + 1],pTexture->image[position]);
	return CRGB(GetRValue(color) / 255.0,GetGValue(color) / 255.0,GetBValue(color) / 255.0);
}
